package com.example.walkera.rtsp_android_client.rtspclient.Stream;

import android.os.HandlerThread;
import android.os.Handler;
import android.util.Log;

import java.util.IllegalFormatCodePointException;
import java.util.concurrent.LinkedBlockingDeque;

/**
 *This class is used to analysis the data from rtp socket , recombine it to video or audio stream
 * 1. get the data from rtp socket
 * 2. put the data into buffer
 * 3. use the thread to get the data from buffer, and unpack it
 */
public abstract class RtpStream {

    private final static String tag = "RtspStream";
    protected final static int TRACK_VIDEO = 0x01;
    protected final static int TRACK_AUDIO = 0x02;
    private final int RTP_FIXED_LENGTH=12;
    private  int streamPack=0;

    private Handler mHandler;
    private byte[] buffer;
    private HandlerThread thread;
    private boolean isStoped;

    //modefy by lihaiping1603@aliyun.com on 2016-01-09
    protected class StreamPacks {
        public int rtp_version;//版本号：2bit
        public boolean padding;//填充:1bit
        public boolean extension;//扩展位：1bit
        public int csrc_count;//cc，csrc定长头字段长度:4bit
        public boolean mark;//mark位：1bit
        public int pt;//playload,负载类型：7bit
        public int sequenceNumber;//序列号：16bit
        public long timestamp;//时间戳:32bit
        public long Ssrc;//域识别同步源：32bit
        public int rtpHeaderLength;//rtp头部长度
        public int paddingLen;//填充数据长度
        public int validDataLen;//有效数据负载长度
        public byte[] data;//负载数据
    }

    private static class bufferUnit {
        public byte[] data;
        public int len;
    }

    private static LinkedBlockingDeque<bufferUnit> bufferQueue = new LinkedBlockingDeque<>();

    public RtpStream() {
        thread = new HandlerThread("RTPStreamThread");
        thread.start();
        mHandler = new Handler(thread.getLooper());
        unpackThread();
        isStoped = false;
    }

    public static void receiveData(byte[] data, int len) {
        bufferUnit tmpBuffer = new bufferUnit();
        tmpBuffer.data = new byte[len];
        System.arraycopy(data,0,tmpBuffer.data,0,len);
        tmpBuffer.len = len;
        try {
            bufferQueue.put(tmpBuffer);
        } catch (InterruptedException e) {
        }
    }

    private void unpackThread() {
        mHandler.post(new Runnable() {
            @Override
            public void run() {
                bufferUnit tmpBuffer;
                while (!isStoped) {
                    try {
                        tmpBuffer = bufferQueue.take();
                        buffer = new byte[tmpBuffer.len];
                        System.arraycopy(tmpBuffer.data,0,buffer,0,tmpBuffer.len);
                        unpackData();
                    } catch (InterruptedException e) {
                        Log.e(tag,"wait the new data into the queue..");
                    }
                }
                buffer = null;
                bufferQueue.clear();
            }
        });
    }

    public void stop(){
        isStoped = true;
        try {
            Thread.sleep(100);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        bufferQueue.clear();
        buffer = null;
        thread.quit();
    }


    protected abstract void recombinePacket(StreamPacks sp);

    private void unpackData() {
        int parsed_length=0;
        StreamPacks tmpStreampack = new StreamPacks();
        if(buffer.length == 0 || buffer.length<=12) return;
        int rtpVersion = (buffer[0]&0xFF)>>6;
        if(rtpVersion != 2) {
            Log.e(tag,"This is not a rtp packet.");
            return;
        }
        //modefy by lihaiping1603@aliyun.com on 2016-01-09
        //第0个字节
        tmpStreampack.rtp_version=rtpVersion;
        tmpStreampack.padding=(buffer[0]&0xFF&0x20)>>5==1;
        tmpStreampack.extension=(buffer[0]&0xFF&0x10)>>4==1;
        tmpStreampack.csrc_count=buffer[0]&0xFF&0x0f;
        //第1个字节
        tmpStreampack.mark = (buffer[1] & 0xFF & 0x80) >> 7 == 1;
        tmpStreampack.pt = buffer[1] & 0x7F;
        //第2,3个字节
        tmpStreampack.sequenceNumber = ((buffer[2] & 0xFF) << 8) | (buffer[3] & 0xFF);
        //第4,5,6,7个字节
        tmpStreampack.timestamp = Long.parseLong(Integer.toHexString(((buffer[4] & 0xFF) << 24) | ((buffer[5]&0xFF) << 16) | ((buffer[6]&0xFF) << 8) | (buffer[7]&0xFF)) , 16);
        //第8,9,10,11个字节
        tmpStreampack.Ssrc = ((buffer[8]&0xFF) << 24) | ((buffer[9]&0xFF) << 16) | ((buffer[10]&0xFF) << 8) | (buffer[11]&0xFF);

        //头部长度最少为12byte+CSRC长度
        parsed_length=RTP_FIXED_LENGTH+tmpStreampack.csrc_count*4;
        if (tmpStreampack.extension){//如果有拓展位
            //跳过defined by profile这个字段的两个字节
            parsed_length+=2;//skip 2 byte for profile

//            int extension_len=buffer[parsed_length]&0xff;
//            extension_len<<=8;
//            extension_len|=buffer[parsed_length+1]&0xff;
//            extension_len+=1;
//            int variable_length =extension_len<<2;

            //解析length字段得到可变长度的大小，length本身长度为2个字节
            int variable_length = (((int)(buffer[parsed_length]&0xff)<<8)+(int)(buffer[parsed_length+1]&0xff))<<2;
            //跳过length字节两个长度
            parsed_length+=2;//skip 2byte for length
            parsed_length+=variable_length;
            Log.d(tag, "unpackData: extension variable length:"+variable_length);
        }
        tmpStreampack.rtpHeaderLength=parsed_length;

        if (tmpStreampack.padding) {//如果有填充bit
            int padding_len = buffer[buffer.length-1];
            if (tmpStreampack.rtpHeaderLength+padding_len<buffer.length){
                tmpStreampack.paddingLen=padding_len;
                Log.d(tag, "unpackData: paddingLen:"+tmpStreampack.paddingLen);
            }
            else{
                tmpStreampack.paddingLen=0;
                Log.d(tag, "unpackData: padding is true,but paddingLen is inValid,so set paddingLen 0");
            }

        }

        //计算有效数据
        tmpStreampack.validDataLen=buffer.length-tmpStreampack.paddingLen-tmpStreampack.rtpHeaderLength;

          //这里只是简单的考虑了固定rtp长度的情况，没有考虑拓展的情况
//        tmpStreampack.data = new byte[buffer.length-12];
//        System.arraycopy(buffer, 12, tmpStreampack.data, 0, buffer.length - 12);

        tmpStreampack.data = new byte[tmpStreampack.validDataLen];
        System.arraycopy(buffer, tmpStreampack.rtpHeaderLength, tmpStreampack.data, 0, tmpStreampack.validDataLen);
        //用于测试调试
        if (streamPack>0)
        {
            if (tmpStreampack.sequenceNumber-streamPack>1)
                Log.d(tag, "unpackData: data:丢包了，seq:"+tmpStreampack.sequenceNumber+" last pack:"+streamPack);

            streamPack=tmpStreampack.sequenceNumber;
        }
        else
            streamPack=tmpStreampack.sequenceNumber;

        recombinePacket(tmpStreampack);

    }

}
